using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using TXLooker.Common;
using TXLooker.Common.Core;
using TXLooker.Common.UI;
using TXLooker.WorkItemExtention.Core;

namespace TXLooker.WorkItemExtention.UI
{
    partial class WorkItemTypesMapControl : UserControl
    {
        private enum NodeType
        {
            Project,
            WorkItemType
        }

        #region ServerProvider

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public WIServerProvider ServerProvider
        {
            get
            {
                return this.m_serverProvider;
            }
            set
            {
                if (object.ReferenceEquals(this.m_serverProvider, value))
                    return;

                if (this.m_serverProvider != null)
                {
                    this.m_serverProvider.NewChildItems -= new TFEventHandler<IEnumerable<WIObject>>(OnNewProjects);
                    this.m_serverProvider.PreRemoveChildItems -= new TFEventHandler<IEnumerable<WIObject>>(OnPreRemoveProjects);
                }

                this.m_serverProvider = value;

                if (this.m_serverProvider != null)
                {
                    this.m_serverProvider.NewChildItems += new TFEventHandler<IEnumerable<WIObject>>(OnNewProjects);
                    this.m_serverProvider.PreRemoveChildItems += new TFEventHandler<IEnumerable<WIObject>>(OnPreRemoveProjects);
                }

                this.RaiseServerProviderChanged();
            }
        }
        private WIServerProvider m_serverProvider = null;

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public event EventHandler ServerProviderChanged
        {
            add { lock (m_syncServerProviderChanged) { this.m_OnServerProviderChangedEH += value; } }
            remove { lock (m_syncServerProviderChanged) { this.m_OnServerProviderChangedEH -= value; } }
        }
        private EventHandler m_OnServerProviderChangedEH = null;

        private readonly object m_syncServerProviderChanged = new object();

        private void RaiseServerProviderChanged()
        {
            CommonGlobal.RaiseEventHandler(this.m_OnServerProviderChangedEH, new object[] { this, EventArgs.Empty }, this.m_syncServerProviderChanged);
        }

        #endregion ServerProvider

        #region ProjectProvider

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public WIProjectProvider ProjectProvider
        {
            get { return this.m_projectProvider; }
            set
            {
                if (object.ReferenceEquals(this.m_projectProvider, value))
                    return;

                this.m_projectProvider = value;
                this.RaiseProjectProviderChanged();
            }
        }
        private WIProjectProvider m_projectProvider = null;

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public event EventHandler ProjectProviderChanged
        {
            add { lock (m_syncProjectProviderChanged) { this.m_OnProjectProviderChangedEH += value; } }
            remove { lock (m_syncProjectProviderChanged) { this.m_OnProjectProviderChangedEH -= value; } }
        }
        private EventHandler m_OnProjectProviderChangedEH = null;

        private readonly object m_syncProjectProviderChanged = new object();

        private void RaiseProjectProviderChanged()
        {
            CommonGlobal.RaiseEventHandler(this.m_OnProjectProviderChangedEH, new object[] { this, EventArgs.Empty }, this.m_syncProjectProviderChanged);
        }

        #endregion ProjectProvider

        #region WorkItemType

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public WorkItemType WorkItemType
        {
            get { return this.m_type; }
            private set
            {
                if (object.ReferenceEquals(this.m_type, value))
                    return;

                this.m_type = value;
                this.RaiseWorkItemTypeChanged();
            }
        }
        private WorkItemType m_type = null;

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public event EventHandler WorkItemTypeChanged
        {
            add { lock (m_syncWorkItemTypeChanged) { this.m_OnWorkItemTypeChangedEH += value; } }
            remove { lock (m_syncWorkItemTypeChanged) { this.m_OnWorkItemTypeChangedEH -= value; } }
        }
        private EventHandler m_OnWorkItemTypeChangedEH = null;

        private readonly object m_syncWorkItemTypeChanged = new object();

        private void RaiseWorkItemTypeChanged()
        {
            CommonGlobal.RaiseEventHandler(this.m_OnWorkItemTypeChangedEH, new object[] { this, EventArgs.Empty }, this.m_syncWorkItemTypeChanged);
        }

        #endregion WorkItemType

        #region event SelectedNodeChanged

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public event EventHandler SelectedNodeChanged
        {
            add { lock (m_syncSelectedNodeChanged) { this.m_OnSelectedNodeChangedEH += value; } }
            remove { lock (m_syncSelectedNodeChanged) { this.m_OnSelectedNodeChangedEH -= value; } }
        }
        private EventHandler m_OnSelectedNodeChangedEH = null;

        private readonly object m_syncSelectedNodeChanged = new object();

        private void RaiseSelectedNodeChanged()
        {
            CommonGlobal.RaiseEventHandler(this.m_OnSelectedNodeChangedEH, new object[] { this, EventArgs.Empty }, this.m_syncSelectedNodeChanged);
        }

        #endregion event SelectedNodeChanged

        private readonly object m_syncServers = new object();
        private Dictionary<WIProjectProvider, TreeNode> m_nodesMAP = new Dictionary<WIProjectProvider, TreeNode>();

        public WorkItemTypesMapControl()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            this.m_tvWITMap.AfterSelect += new TreeViewEventHandler(OnTreeViewAfterNodeSelect);

            WIObjectsStore.NewServers += new TFEventHandler<IEnumerable<WIServerProvider>>(OnNewServers);
            WIObjectsStore.PreRemoveServers += new TFEventHandler<IEnumerable<WIServerProvider>>(OnPreRemoveServers);

            this.m_cbxServers.SelectedIndexChanged += new EventHandler(OnCbxServersSelectedIndexChanged);
            this.m_cbxServers.DisplayMember = "ServerName";

            lock (this.m_syncServers)
            {
                this.m_cbxServers.DataSource = new List<WIServerProvider>(WIObjectsStore.Servers);
            }
        }
        private void OnCbxServersSelectedIndexChanged(object sender, EventArgs args)
        {
            this.ServerProvider = this.m_cbxServers.SelectedItem as WIServerProvider;
            if (object.ReferenceEquals(this.ServerProvider, null)) return;


            this.LoadTree(this.ServerProvider);
        }
        private void OnNewServers(object sender, IEnumerable<WIServerProvider> servers)
        {
            MethodInvoker invoker =
                delegate
                {
                    foreach (WIServerProvider item in servers)
                        this.m_cbxServers.Items.Add(item);
                };

            lock (this.m_syncServers)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(invoker);
                }
                else
                {
                    invoker();
                }
            }
        }
        private void OnPreRemoveServers(object sender, IEnumerable<WIServerProvider> servers)
        {
            MethodInvoker invoker =
                delegate
                {
                    foreach (WIServerProvider item in servers)
                        this.m_cbxServers.Items.Remove(item);
                };

            lock (this.m_syncServers)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(invoker);
                }
                else
                {
                    invoker();
                }
            }
        }
        private void OnNewProjects(object sender, IEnumerable<WIObject> projects)
        {
            List<WIProjectProvider> items = new List<WIProjectProvider>();

            foreach (WIProjectProvider p in projects)
            {
                items.Clear(); items.Add(p);
                this.AddProjectsToTree(items);
            }
        }
        private void OnPreRemoveProjects(object sender, IEnumerable<WIObject> projects)
        {
            lock (this.m_nodesMAP)
            {
                foreach (WIProjectProvider item in projects)
                {
                    try
                    {
                        TreeNode node = this.m_nodesMAP[item];
                        this.m_nodesMAP.Remove(item);
                    }
                    catch (System.Exception ex)
                    {
                        Debug.WriteLine(ex.ToString());
                    }
                }
            }
        }
        private void OnTreeViewAfterNodeSelect(object sender, TreeViewEventArgs args)
        {
            TreeNodeTag<NodeType> tag = args.Node.Tag as TreeNodeTag<NodeType>;

            switch (tag.NodeType)
            {
                case NodeType.Project:
                    this.ProjectProvider = tag.Tag as WIProjectProvider;
                    this.WorkItemType = null;
                    break;
                case NodeType.WorkItemType:
                    this.ProjectProvider = (args.Node.Parent.Tag as TreeNodeTag<NodeType>).Tag as WIProjectProvider;
                    this.WorkItemType = tag.Tag as WorkItemType;
                    break;
                default:
                    throw new NotImplementedException();
            }

            this.RaiseSelectedNodeChanged();
        }

        private void LoadTree(WIServerProvider serverProvider)
        {
            this.m_tvWITMap.Nodes.Clear();

            lock (this.m_nodesMAP)
            {
                this.m_nodesMAP.Clear();
            }

            this.AddProjectsToTree(serverProvider.Projects);
        }
        private void AddProjectsToTree(IEnumerable<WIProjectProvider> projects)
        {
            foreach (WIProjectProvider provider in projects)
            {
                TreeNode node = InitProjectBrunch(provider);
                this.m_tvWITMap.Nodes.Add(node);

                lock (this.m_nodesMAP)
                {
                    this.m_nodesMAP.Add(provider, node);
                }
            }
        }
        private TreeNode InitProjectBrunch(WIProjectProvider projectProvider)
        {
            TreeNode node = new TreeNode(projectProvider.ProjectName);
            node.Tag = new TreeNodeTag<NodeType>(NodeType.Project, projectProvider);

            try
            {
                Project project = projectProvider.GetProject();

                foreach (WorkItemType witype in project.WorkItemTypes)
                {
                    TreeNode child = new TreeNode(witype.Name);
                    child.Tag = new TreeNodeTag<NodeType>(NodeType.WorkItemType, witype);

                    node.Nodes.Add(child);
                }
            }
            catch (System.Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }

            return node;
        }

    }
}

//===================================================================================================
